

//OS
#include <jxos_config.h>
#if (JXOS_TASK_ENABLE == 1)
#include "../kernel/jxos_task.h"
#endif
#if (JXOS_ENENT_ENABLE == 1)
#include "../kernel/jxos_event.h"
#endif

//LIB
#include "../lib/software_timer.h"

//SYS
#if (JXOS_SYS_SERVICE_DEBUG_PRINT_TASK_ENABLE == 1)
#include "debug_print_task.h"
#endif
#if (JXOS_SYS_SERVICE_POWER_MGR_TASK_ENABLE == 1)
#include "power_mgr_task.h"
#endif

#if (JXOS_SYS_SERVICE_SOFTWARE_TIMER_TASK_ENABLE == 1)

void (*sys_software_timer_task_hal_init_callback)(void) = 0;
void (*sys_software_timer_task_hal_start_callback)(void) = 0;
void (*sys_software_timer_task_hal_stop_callback)(void) = 0;
uint16_t (*sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback)(uint16_t next_interrupt_time_in_ms) = 0;

#if (TIMER_DYNAMIC_CHANGE_ENABLE == 1)
uint16_t (*sys_software_timer_task_hal_get_passed_time_callback)(void) = 0;
#endif

/***********************************************************/
#if (JXOS_ENENT_ENABLE == 1)&&(JXOS_Compiler_optimization_2 == 0)
static JXOS_EVENT_HANDLE software_timer_task_tick_event;
#else
bool_t software_timer_task_tick_handler_flag;
#endif
#if (JXOS_ENENT_ENABLE == 1)
static JXOS_EVENT_HANDLE software_timer_task_change_event;
#else
bool_t software_timer_task_change_flag;
#endif

static SoftwareTimer_Group_STRUCT swt_group;
static SoftwareTimer_STRUCT swt_space[SWTIMER_MAX];

static uint8_t tick_happened_falg = 0;

#ifdef TIMER_CONSTANT_INTERVAL_MS
static uint32_t tick_ms = 0;
#endif

#if (TIMER_DYNAMIC_CHANGE_ENABLE == 1)
static void timer_change(void)
{
	uint16_t time = 0;

	//get passed time
	if(sys_software_timer_task_hal_get_passed_time_callback != 0){
		time = sys_software_timer_task_hal_get_passed_time_callback();
	}
	//swt_group refresh
	software_timer_group_handler(&swt_group, time);

	//calculate next_interrupt_time
	if(software_timer_group_check_running_all(&swt_group) != 0){
		time = software_timer_group_find_minimum_time(&swt_group);
	}
	else{
		time = 0;
		if(sys_software_timer_task_hal_stop_callback != 0){
			sys_software_timer_task_hal_stop_callback();
		}
	}
	//set next interrupt
	if(time != 0){
		if(sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback != 0){
			sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback(time);
		}
	}
}
#else
static void timer_change(void)
{
#ifdef TIMER_CONSTANT_INTERVAL_MS
	//swt_group refresh
	software_timer_group_handler(&swt_group, TIMER_CONSTANT_INTERVAL_MS);

	if(software_timer_group_check_running_all(&swt_group) == 0){
		if(sys_software_timer_task_hal_stop_callback != 0){
			sys_software_timer_task_hal_stop_callback();
		}
	}
#else
	static uint16_t last_wakeup_time = 0;
	//swt_group refresh
	software_timer_group_handler(&swt_group, last_wakeup_time);

	//calculate next_interrupt_time
	if(software_timer_group_check_running_all(&swt_group) != 0){
		last_wakeup_time = software_timer_group_find_minimum_time(&swt_group);
	}
	else{
		last_wakeup_time = 0;
		if(sys_software_timer_task_hal_stop_callback != 0){
			sys_software_timer_task_hal_stop_callback();
		}
	}
	//set next interrupt
	if(last_wakeup_time != 0){
		if(sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback != 0){
			last_wakeup_time = sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback(last_wakeup_time);
		}
	}
#endif
}
#endif

#if (JXOS_Compiler_optimization_2 == 1)||(JXOS_ENENT_ENABLE == 0)

#else
void software_timer_task_tick_handler(void)
{
#ifdef TIMER_CONSTANT_INTERVAL_MS
	tick_ms += TIMER_CONSTANT_INTERVAL_MS;
#endif
	jxos_event_set(software_timer_task_tick_event);
}
#endif

#if (JXOS_Compiler_optimization_1 == 1)
#if (JXOS_TASK_ENABLE == 1)
static void software_timer_task(void)
#else
void sys_software_timer_task(void)
#endif
#else
static void software_timer_task(uint8_t task_id, void * parameter)
#endif
{
#if (JXOS_Compiler_optimization_2 == 1)||(JXOS_ENENT_ENABLE == 0)
	if(software_timer_task_tick_handler_flag == true){
		software_timer_task_tick_handler_flag = false;
#else
	if(jxos_event_wait(software_timer_task_tick_event) == 1){
#endif
		tick_happened_falg = 1;
		timer_change();
	}

#if (JXOS_ENENT_ENABLE == 0)
	if(software_timer_task_change_flag == true){
		software_timer_task_change_flag = false;
#else
	if(jxos_event_wait(software_timer_task_change_event) == 1){
#endif
		if(sys_software_timer_task_hal_start_callback != 0){
			sys_software_timer_task_hal_start_callback();
		}
		timer_change();
	}
}

uint8_t software_timer_task_get_tick_happened(void)
{
	return tick_happened_falg;
}

void software_timer_task_reset_tick_happened(void)
{
	tick_happened_falg = 0;
}

void sys_software_timer_task_init(void)
{
	//HAL
	if(sys_software_timer_task_hal_init_callback != 0){
		sys_software_timer_task_hal_init_callback();
	}
	//OS
#if (JXOS_TASK_ENABLE == 1)
	jxos_task_create(software_timer_task, "swt_t", 0);
#endif
#if (TIMER_DYNAMIC_CHANGE_ENABLE == 1)&&(JXOS_Compiler_optimization_2 == 0)
	software_timer_task_tick_event = jxos_event_create();
#else
	software_timer_task_tick_handler_flag = false;
#endif
#if (JXOS_ENENT_ENABLE == 1)
	software_timer_task_change_event = jxos_event_create();
#else
	software_timer_task_change_flag = false;
#endif

	//LIB
    software_timer_group_init(&swt_group,
                               SWTIMER_MAX,
                               swt_space);

	if(sys_software_timer_task_hal_start_callback != 0){
		sys_software_timer_task_hal_start_callback();
	}



	//SYS TASK
}

/***********************************************************/
SoftwareTimer_STRUCT* sys_software_timer_task_new_timer(void)
{
    SoftwareTimer_STRUCT* swt;
	swt = software_timer_create(&swt_group, 0);
	if(swt == 0){
#if (JXOS_SYS_SERVICE_DEBUG_PRINT_TASK_ENABLE == 1)
        sys_debug_print_task_sys_ser_print_str("create_new_timer error");
#endif
	}
	return swt;
}

void sys_software_timer_task_set_timer(SoftwareTimer_STRUCT* swtime_id, uint16_t time)
{
	software_timer_set_timeout(swtime_id, time);
#if (JXOS_ENENT_ENABLE == 0)
	software_timer_task_change_flag = true;
#else
	jxos_event_set(software_timer_task_change_event);
#endif
}

void sys_software_timer_task_start_timer(SoftwareTimer_STRUCT* swtime_id)
{
	software_timer_start(swtime_id);
#if (JXOS_ENENT_ENABLE == 0)
	software_timer_task_change_flag = true;
#else
	jxos_event_set(software_timer_task_change_event);
#endif
}

void sys_software_timer_task_stop_timer(SoftwareTimer_STRUCT* swtime_id)
{
	software_timer_stop(swtime_id);
}

void sys_software_timer_task_restart_timer(SoftwareTimer_STRUCT* swtime_id)
{
	software_timer_restart(swtime_id);
#if (JXOS_ENENT_ENABLE == 0)
	software_timer_task_change_flag = true;
#else
	jxos_event_set(software_timer_task_change_event);
#endif
}

uint8_t sys_software_timer_task_check_running_timer(SoftwareTimer_STRUCT* swtime_id)
{
	return software_timer_check_running(swtime_id);
}

uint8_t sys_software_timer_task_check_overtime_timer(SoftwareTimer_STRUCT* swtime_id)
{
    return software_timer_check_overtime(swtime_id);
}

#ifdef TIMER_CONSTANT_INTERVAL_MS
uint32_t sys_software_timer_task_get_tick_ms(void)
{
    return tick_ms;
}

uint32_t sys_software_timer_task_calculate_interval_tick_ms(uint32_t last_tick, uint32_t this_tick)
{
	uint32_t time;

	if(this_tick >= last_tick){
		time = this_tick - last_tick;
	}
	else{
		time = (((0xFFFFFFFF - last_tick) + 1) + this_tick);
	}

	return time;
}
#endif


#endif
